package com.module.boots.api.aspect;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import com.google.common.util.concurrent.RateLimiter;
import com.module.boots.api.utils.HttpContextUtils;
import com.module.boots.api.utils.MsgUtils;
import com.module.boots.exception.CommonRuntimeException;

import lombok.extern.slf4j.Slf4j;

/**
 * 请求限流
 * @author:溪云阁
 * @date:2020年5月2日
 */
@Aspect
@Component
@Slf4j
public class RequestLimit {

    // 每秒产生150个令牌
    private static final RateLimiter RATE_LIMITER = RateLimiter.create(150);

    /**
     * 拦截移动端请求接口
     * @author 溪云阁
     * void
     */
    @Pointcut("execution( * com.atomic.*.application..application.*.*(..))")
    public void applicationPointCut() {
    }

    /**
     * 拦截电脑端请求接口
     * @author 溪云阁
     * void
     */
    @Pointcut("execution( * com.atomic.*.view..controller.*.*(..))")
    public void viewPointCut() {
    }

    /**
     * 拦截外部/第三方请求接口
     * @author 溪云阁
     * void
     */
    @Pointcut("execution( * com.atomic.*.external..external.*.*(..))")
    public void externalPoint() {

    }

    @Before("applicationPointCut() || viewPointCut() || externalPoint()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {

    }

    @AfterReturning(returning = "ret", pointcut = "applicationPointCut() || viewPointCut() || externalPoint()")
    public void doAfterReturning(Object ret) throws Throwable {
    }

    @Around("applicationPointCut() || viewPointCut() || externalPoint()")
    public Object doAround(ProceedingJoinPoint pjp) {
        Object obj = null;
        try {
            final HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
            final HttpServletResponse response = HttpContextUtils.getHttpServletResponse();
            if (RATE_LIMITER.tryAcquire()) {
                // 执行方法
                obj = pjp.proceed();
            } else {
                // 拒绝了请求（服务降级）
                log.info("拒绝了请求：" + request.getRequestURI());
                response.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
                response.setContentType("application/json;charset=UTF-8");
                response.getOutputStream().write(MsgUtils.buildFailureMsg("服务器繁忙,稍后再试").toString().getBytes("utf-8"));
            }
        }
        catch (final Throwable e) {
            log.error("限流出现问题:", e.fillInStackTrace());
            throw new CommonRuntimeException(e.getMessage());
        }
        return obj;
    }

}
